package person.twj.jwt.core.security.handler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import person.twj.jwt.core.security.constant.TokenConstants;
import person.twj.jwt.core.security.util.UserToken;
import person.twj.jwt.core.security.util.TokenUtil;
import person.twj.jwt.domain.vo.RsVo;

import java.io.BufferedReader;
import java.io.IOException;

public class MyUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {


    // 只允许使用post请求
    private boolean postOnly = true;

    public MyUsernamePasswordAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
        super(defaultFilterProcessesUrl, authenticationManager);
        LoginPostHandler loginPostHandler = new LoginPostHandler();
        setAuthenticationFailureHandler(loginPostHandler);
        setAuthenticationSuccessHandler(loginPostHandler);

    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        /*if(!requiresAuthentication(request,response)){ // 这个在 AbstractAuthenticationProcessingFilter 开始就已经过滤了
            // 路径是否是 defaultFilterProcessesUrl
            return null;
        }*/
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        // 获取json格式传参
        JsonNode jsonNode =getJSON(request);

        String username = jsonNode.get(TokenConstants.USERNAME).asText();
        username = (username != null) ? username.trim() : "";
        String password = jsonNode.get(TokenConstants.PASSWORD).asText();
        password = (password != null) ? password : "";
        // 组装成 没认证的token，给AuthenticationManager 去真正的验证
        UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken
                .unauthenticated(username,password);

        // 这里是使用 DaoAuthenticationProvider 来验证身份。
        // 1. 验证成功后，会交给AuthenticationSuccessHandler去处理
        // 2. 验证失败后，会交给AuthenticationFailureHandler去处理
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    private JsonNode getJSON(HttpServletRequest request) {
        try {
            // 1. 从HttpServletRequest对象中获取输入流，并读取请求正文。
            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = request.getReader();
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            String requestBody = buffer.toString();
            // 2. 使用JSON库（如Jackson、Gson等）将字符串解析为JsonNode或任何其他适合你的数据结构。
            ObjectMapper mapper = new ObjectMapper(); // Jackson JSON库示例
            JsonNode jsonNode = mapper.readTree(requestBody); // 解析为JsonNode对象
            return jsonNode;
        }catch (Exception e){
            e.printStackTrace();
            throw new AuthenticationCredentialsNotFoundException("获取json传参失败") ;
        }

    }


    class LoginPostHandler implements AuthenticationFailureHandler, AuthenticationSuccessHandler {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
            if(e instanceof BadCredentialsException) {
                RsVo.failed(1,"用户名或密码错误").writeTo(response);

            } else {
                RsVo.failed(-1,"未知错误").writeTo(response);
            }
        }

        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
            UserToken userToken = (UserToken) authentication.getPrincipal();
            // token里不存在用户密码
            RsVo.success("登录成功", map -> {
                        map.put("access_token", TokenUtil.createToken(userToken));//有效期2个小时
                        map.put("refresh_token", TokenUtil.createRefreshToken(userToken));//有效期12小时
                        map.put("expires_in", TokenConstants.EXPIRES_IN);
                    })
                    .writeTo(response);
        }
    }
}
